#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "uglies.h"
#include "modes.h"

extern struct mode modes[];
extern int num_commands;
extern struct command **commands;

int find_separator(char *string)
{
	int i;
	for (i = 0; i < strlen(string); i++)
	{
		if (string[i] == UGLIES_SEP)
		{
			return i;
		}
	}

	return -1;
}

char *make_argument(struct arguments *dest, char *line, int f, int s)
{
	line[f] = '\0';
	line[f+s+1] = '\0';

	dest->name = (char *)malloc(strlen(line)+1);
	memcpy(dest->name, line, f);
	dest->name[f] = '\0';

	dest->value = (char *)malloc(strlen(&(line[f+1]))+1);
	memcpy(dest->value, &(line[f+1]), s);
	dest->value[s] = '\0';

	return &(line[f+s+2]);
}

void parse_uglies_line(char *uglies_line)
{
	int i;
	struct command *command;

	/* Allow comments starting with a pound sign. */

	if (uglies_line[0] == '#') return;

	/* I need to remember what this actually does... */

	command = (struct command *)malloc(sizeof(struct command));
	command->num_history_points = 0;
	command->args = (struct arg_group *)malloc(sizeof(struct arg_group));
	command->args->length = 0;
	command->args->args = NULL;

	/* Extract mode name */

	i = find_separator(uglies_line);
	if (i == -1)
	{
		printf("ERR: Could not find mode name.\n");
		return;
	}

	uglies_line[i] = '\0';
	command->mode_num = get_mode_by_name(uglies_line);
	if (command->mode_num == -1)
	{
		printf("ERR: get_mode_by_name returned -1\n");
		return;
	}

	uglies_line = &(uglies_line[i+1]);

	while(1)
	{
		int first_sep = 0, second_sep = 0;

		first_sep = find_separator(uglies_line);

		if (first_sep == -1)
		{
			command->command = (char *)malloc(strlen(uglies_line));
			memcpy(command->command, uglies_line,
				strlen(uglies_line));
			command->wake = time(NULL);

			num_commands++;
			commands = (struct command **)realloc(commands,
				sizeof(struct command **) * num_commands);
			commands[num_commands-1] = command;

			/* modes[command->mode_num].pt2func(command); */
			
			return;
		}

		second_sep = find_separator(&(uglies_line[first_sep+1]));
		if (second_sep == -1)
		{
			/* Invalid syntax */
			printf("Could not find second separator: %s\n",
				&(uglies_line[first_sep+1]));
			return;
		}

		command->args->length++;
		command->args->args =
			(struct arguments *)realloc(command->args->args,
			sizeof(struct arguments) * command->args->length);

		make_argument(&(command->args->args[command->args->length-1]),
			uglies_line, first_sep, second_sep);

		uglies_line = &(uglies_line[second_sep+first_sep+2]);
	}
}

void parse_uglies()
{
	char buffer[MAX_UGLIES_LENGTH];
	int do_continue = 1;
	int more_file = 1;
	int buffer_length = 0;
	int found_newline = 0;
	int i;
	FILE *parsers = fopen("conf/uglies.conf", "rb");
	if (!parsers)
	{
		printf("Unable to open conf/uglies.conf\n");
		return;
	}

	/* While we are marked as needing to continue. */
	while (do_continue)
	{
		/* An inner block to read more data from the file if there
		   is room to fit more data and there is data left to be
		   read.
		*/
		if (more_file)
		{
			/* Decide how much we should read, and keep track
			   of how much is actually in the buffer.
			*/
			int to_read = MAX_UGLIES_LENGTH - buffer_length;
			int did_read = fread(&(buffer[buffer_length]), 1,
			                     to_read, parsers);
			buffer_length += did_read;

			/* Did something significant happen? This happens
			   both on errors and at the end of a file.
			*/
			if (did_read == 0)
			{
				if (feof(parsers))
				{
					more_file = 0;
				}
				else if (ferror(parsers))
				{
					perror("Error reading uglies file.");
					exit(-1);
				}
			}
		}
		
		found_newline = 0;
		for (i = 0; i < buffer_length; i++)
		{
			if (buffer[i] == '\n' || buffer[i] == '\r')
			{
				found_newline = 1;
				buffer[i] = '\0';
				parse_uglies_line(buffer);
				memmove(buffer, &(buffer[i+1]),
					MAX_UGLIES_LENGTH - (i + 1));
				buffer_length -= (i + 1);
				break;
			}
		}
		if (!found_newline && !more_file)
		{
			buffer_length = 0;
		}

		/* Are we done? */
		if (!buffer_length)
			do_continue = 0;
	}

	fclose(parsers);
}


